package top.canyue.word_range_service.service.impl;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import top.canyue.word_range.exception.ParamNullException;
import top.canyue.word_range.pojo.dto.LoginDto;
import top.canyue.word_range.pojo.dto.LoginUser;
import top.canyue.word_range.pojo.dto.UserDto;
import top.canyue.word_range.pojo.po.User;
import top.canyue.word_range.pojo.vo.LoginResponseVo;
import top.canyue.word_range.pojo.vo.UserVo;
import top.canyue.word_range.result.Result;
import top.canyue.word_range.utils.JwtUtil;
import top.canyue.word_range.utils.PojoUtil;
import top.canyue.word_range_service.service.UserLoginService;
import top.canyue.word_range_service.service.UserService;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class UserLoginServiceImpl implements UserLoginService {
    final AuthenticationManager authenticationManager;
    private final JwtUtil jwtUtil = new JwtUtil();
    @Resource
    private RedisTemplate<String,LoginUser> redisTemplate;
    @Resource
    private ValueOperations<String, LoginUser> valueOperations;
    final PasswordEncoder passwordEncoder;
    final UserService userService;
    // 登录超时时间(Redis数据的TTL)
    @Value("${work-range.user.login-timeout}")
    private int userLoginTimeout;
    // Redis数据前缀
    @Value("${work-range.redis.key-prefix}")
    private String redisKeyPrefix;

    @Override
    public Result<LoginResponseVo> login(LoginDto loginDto){
        String phone = loginDto.getPhone();
        if(loginDto.getPhone() == null ){
            throw new ParamNullException();
        }
        String password = loginDto.getPassword();
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(phone, password);
        try {
            Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
            if (Objects.isNull(authenticate)) {
                return Result.error("登录失败");
            }
            LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
            User user = loginUser.getUser();
            String token = jwtUtil.createToken(loginUser);
            List<String> permissions = loginUser.getPermissions();
            valueOperations.set(redisKeyPrefix + ":" + user.getId(),loginUser);
            redisTemplate.expire(redisKeyPrefix + user.getId(),userLoginTimeout, TimeUnit.SECONDS);
            return Result.success(
                    new LoginResponseVo(token, user.getId(), permissions)
            );
        }catch (Exception e){
            return Result.error(e.getMessage());
        }
    }

    @Override
    public Result<UserVo> getUserByToken(String JWT){
        String userId = jwtUtil.getUserIdFromToken(JWT);
        User loginUser = Objects.requireNonNull(valueOperations.get(redisKeyPrefix + ":" + userId)).getUser();
        UserVo userVo = BeanUtil.copyProperties(loginUser, UserVo.class, PojoUtil.getNullPropertyNames(User.class));
        return Result.success(userVo);
    }

    @Override
    public Result<Object> logout() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder
                .getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String loginUserId = loginUser.getUser().getId();
        Boolean ok = redisTemplate.delete(redisKeyPrefix + ":" + loginUserId);
        if(Boolean.FALSE.equals(ok)){
            return Result.error("注销失败");
        }
        return Result.success();
    }

    @Override
    public Result<Object> logon(UserDto userDto){
        if(userDto.getPhone() == null){
            throw new ParamNullException();
        }
        String passwordHash = passwordEncoder.encode(userDto.getPassword());
        User userPo = userDto.toPo();
        userPo.setPasswordHash(passwordHash);
        boolean ok = userService.save(userPo);
        if(! ok){
            return Result.error("注册失败");
        }
        return Result.success();
    }

}
